home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Visual Basic Toolbox
/
Visual Basic Toolbox (P.I.E.)(1996).ISO
/
clocks
/
ttcode
/
modblast.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-10-20
|
20KB
|
657 lines
//---------------------------------------------------------------------------
// modblast.c
//---------------------------------------------------------------------------
// Contains control procedure for ModBlaster control
//---------------------------------------------------------------------------
#define NOCOMM
#include <windows.h>
#include <vbapi.h>
#include <string.h>
#define CTL_DATA
#include "modblast.h"
//---------------------------------------------------------------------------
// Global Variables
//---------------------------------------------------------------------------
HANDLE hmodDLL;
CONTROLSTUFF controls[MAX_MSGBLASTERS];
HANDLE taskDevEnvironment = NULL;
//---------------------------------------------------------------------------
// Utility Functions - added by BJ 1/15/94
//---------------------------------------------------------------------------
WORD FAR PASCAL _export mbLoWord(DWORD dword)
{
return (WORD)dword;
}
WORD FAR PASCAL _export mbHiWord(DWORD dword)
{
return (WORD)(dword >> 16);
}
WORD FAR PASCAL _export mbGetControlIndex(HWND hwnd)
{
DWORD index;
HCTL hCtl;
if ((hCtl = VBGetHwndControl(hwnd)) &&
(VBGetControlProperty(hCtl, IPROP_STD_INDEX, (LPVOID)&index) == 0))
return (WORD)index;
else
return (WORD)-1;
}
ULONG FAR PASCAL _export mbSetControlFlags(HWND hwnd, ULONG mask, ULONG value)
{
return VBSetControlFlags(VBGetHwndControl(hwnd), mask, value);
}
//---------------------------------------------------------------------------
// MsgBlaster Control Procedure
//---------------------------------------------------------------------------
LONG FAR PASCAL _export MsgBlasterCtlProc(HCTL hctl, HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
switch (msg)
{
case WM_NCCREATE:
{
int i;
// deref MsgBlaster control struct now - valid until we call VB procedure (BJ)
PMSGBLASTER lpMsgBlaster = LpblastDEREF(hctl);
// Look for an open slot in the array and save the hctl
for(i = 0; i < MAX_MSGBLASTERS; i++)
{
if(controls[i].hctlMain == NULL)
{
controls[i].hctlMain = hctl;
break;
}
}
// If users are trying to use this many blasters, then they are
// probably doing something wrong. Besides, using 25 blasters would
// slow down the entire system
if (i == MAX_MSGBLASTERS)
{
MessageBox(hwnd, "Too many message blasters", "Error!", MB_OK);
return(0);
}
// make sure that the hWndTargets are zeroed out.
lpMsgBlaster->hWndTarget = NULL;
// initialize the passage var to pass msgs onto the origproc
// after firing the event. This is the default behavior.
// There was a bug here - replaced MAX_MSGBLASTERS with MAX_TRAPPABLEMSGS (BJ)
for(i = 0; i < MAX_TRAPPABLEMSGS; i++)
lpMsgBlaster->MsgPassage[i] = 1;
VBSetControlProperty(hctl, IPROP_MSGBLASTER_ABOUTBOX,
(LONG)(LPSTR)"Click on \"...\" for the About Box ---->");
}
break;
case VBM_SETPROPERTY:
switch(wp)
{
case IPROP_MSGBLASTER_HWNDTARGET:
{
int i, j;
// we only process this message if we are in run mode
if (VBGetMode() != MODE_DESIGN)
{
// deref MsgBlaster control struct now - valid until we call VB procedure (BJ)
PMSGBLASTER lpMsgBlaster = LpblastDEREF(hctl);
// find the next slot and save the hWndTarget
for(i = 0; i < MAX_MSGBLASTERS; i++)
{
if(controls[i].hctlMain == hctl)
{
// Check to see if this blaster is already being
// used to subclass a control
// if it is, un-subclass it.
// This could happen when the vb programmer changes
// the target control at run time
if(controls[i].hWndTarget) {
UnSubClass(controls[i].hWndTarget,hctl);
// initialize messages and passage when target changes (BJ)
for(j = 0; j < MAX_TRAPPABLEMSGS; j++) {
lpMsgBlaster->MsgList[j] = 0;
lpMsgBlaster->MsgPassage[j] = 1;
}
}
controls[i].hWndTarget = (HWND)lp;
break;
}
}
// sublcass the target control
// only if target not == NULL (BJ)
if ((HWND)lp != NULL && !FSubClass((HWND)lp))
MessageBox(hwnd, "Unable to subclass control", "Error", MB_OK);
}
}
return 0L;
case IPROP_MSGBLASTER_MSGLIST:
{
// This is where we store the list of messages to trap
// normally, the vb programmer will load this in the
// form load event.
LONG i;
LPDATASTRUCT lpDs = (LPDATASTRUCT)lp;
i = lpDs->index[0].data;
// I put an arbitrary limit on the number of messages
// that could be trapped. My think is that they really shouldn't
// be doing a lot of message processing in VB.
if (i < 0 || i >= MAX_TRAPPABLEMSGS)
return ERRBADINDEX;
LpblastDEREF(hctl)->MsgList[i] = (UINT)lpDs->data;
return 0L;
}
case IPROP_MSGBLASTER_MSGPASSAGE:
{
// This property determines how each message will be processed
// There are 3 valid possibilities; -1, 0, 1.
// -1 means preprocess the message. This means pass it on to the
// VBDefControlProc first
// 0 means eat the message. i.e. never pass it on
// 1 means pass the message on after firing the event
// This is the default.
LONG i;
LPDATASTRUCT lpDs = (LPDATASTRUCT)lp;
i = lpDs->index[0].data;
if (i < 0 || i >= MAX_TRAPPABLEMSGS)
return ERRBADINDEX;
LpblastDEREF(hctl)->MsgPassage[i] = (SHORT)lpDs->data;
return 0L;
}
}
break;
case VBM_GETPROPERTY:
switch(wp)
{
case IPROP_MSGBLASTER_MSGLIST:
{
LONG i;
LPDATASTRUCT lpDs = (LPDATASTRUCT)lp;
i = lpDs->index[0].data;
if (i < 0 || i >= MAX_TRAPPABLEMSGS)
return ERRBADINDEX;
lpDs->data = (LONG)LpblastDEREF(hctl)->MsgList[i];
return 0L;
}
case IPROP_MSGBLASTER_MSGPASSAGE:
{
LONG i;
LPDATASTRUCT lpDs = (LPDATASTRUCT)lp;
i = lpDs->index[0].data;
if (i < 0 || i >= MAX_TRAPPABLEMSGS)
return ERRBADINDEX;
lpDs->data = LpblastDEREF(hctl)->MsgPassage[i];
return 0L;
}
case IPROP_MSGBLASTER_HWNDTARGET:
{
LONG i;
LPDATASTRUCT lpDs = (LPDATASTRUCT)lp;
i = lpDs->index[0].data;
if (i < 0 || i >= MAX_TRAPPABLEMSGS)
return ERRBADINDEX;
lpDs->data = LpblastDEREF(hctl)->hWndTarget;
return 0L;
}
} // end of switch
break;
case VBM_INITPROPPOPUP:
if(wp == IPROP_MSGBLASTER_ABOUTBOX)
{
HWND hwndList = (HWND)LOWORD(lp);
return (LONG)HwndInitAboutBox();
}
break;
case IPROP_MSGBLASTER_ABOUTBOX:
// force a repaint
InvalidateRect(hwnd, NULL, FALSE);
break;
case WM_NCDESTROY:
if(LpblastDEREF(hctl)->hszAbout)
VBDestroyHsz(LpblastDEREF(hctl)->hszAbout);
break;
case WM_DESTROY:
{
int i;
// find which control we are dealing with
for(i = 0; i < MAX_MSGBLASTERS; i++)
if(controls[i].hctlMain == hctl)
break;
// ****>>> We *must* unsubclass the hwndTarget when
// this hctl goes away!
UnSubClass(controls[i].hWndTarget,hctl);
controls[i].hWndTarget = NULL;
controls[i].hctlMain = NULL;
}
break;
}
return VBDefControlProc(hctl, hwnd, msg, wp, lp);
}
//---------------------------------------------------------------------------
// Sub class routine for target control window proc.
//---------------------------------------------------------------------------
LONG FAR PASCAL _export SubClassProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
LONG rc;
int i, j;
UINT m;
HCTL hctlMain;
// find the correct hctlMain
// I could have called FindhctlMain, but I wanted to avoid the overhead
// we need the most speed we can get in this routine.
for(j = 0; j < MAX_MSGBLASTERS; j++)
if(controls[j].hWndTarget == hwnd)
break;
// The first part of this if is a sanity check
if(j == MAX_MSGBLASTERS)
MessageBox(hwnd, "Big trouble. We're gonna die.", "TROUBLE", MB_OK);
else
hctlMain = controls[j].hctlMain;
for (i=0; i < MAX_TRAPPABLEMSGS; i++)
{
// Get out of the loop if hctlMain is no longer valid
// ****>>> Since you fire an event, it is possible for hctlMain to
// disappear during that event, so you must check to see if hctlMain
// is still non-NULL. This is also why I added the NULLing out of
// this variable to the WM_DESTROY case.
if (!hctlMain)
break;
// ****>>> Firing an event invalidates pMsgBlaster!!!!
// You MUST deref it each time through this loop!!!
m = LpblastDEREF(hctlMain)->MsgList[i];
// Get out of the loop if no more messages
if (!m)
break;
if (msg == m)
{
int eat;
// now that we have a hit, determine if we should pass the
// msg on to the orig proc first, last or
// do we eat the msg entirely
eat = LpblastDEREF(hctlMain)->MsgPassage[i];
switch(eat)
{
case -1: // call the orig proc first
rc = CallWindowProc(LpblastDEREF(hctlMain)->lpfnOrigProc,
hwnd, msg, wp, lp);
rc = FireMessage(hctlMain, msg, wp, lp, rc);
if (msg == WM_DESTROY)
{
MessageBox(hwnd,
"Can't call original proc with WM_DESTROY prior to firing event.",
"Error", MB_OK);
break;
}
return rc;
case 0: // eat the message
rc = FireMessage(hctlMain, msg, wp, lp, rc);
if (msg == WM_DESTROY)
{
MessageBox(hwnd,
"Can't eat WM_DESTROY message.",
"Error", MB_OK);
break;
}
return rc;
case 1: // pass it on afterward
rc = FireMessage(hctlMain, msg, wp, lp, rc);
break;
case 2: // pass it on afterward - MAYBE - BJ
rc = FireMessage(hctlMain, msg, wp, lp, rc);
// if the return code is 0 then the message has been handled - BJ
if (rc == 0) return rc;
break;
default:
MessageBox(hwnd,
"Default case in passage test. Should never get.",
"Error", MB_OK);
break;
}
}
}
// Call the original Window Procedure
rc = CallWindowProc(LpblastDEREF(hctlMain)->lpfnOrigProc, hwnd, msg, wp, lp);
// ****>>> Strictly speaking, it is not necessary to unsubclass this window
// since it is being destroyed, but UnSubClass() does *need* to reset the
// necessary global variables, and modular programming says we shouldn't
// do that from here, when UnSubClass() can do that for us...
if (msg == WM_DESTROY)
UnSubClass(hwnd, hctlMain);
return rc;
}
//--------------------------------------------------------------------------
// Fire the msg event
//--------------------------------------------------------------------------
LONG NEAR FireMessage(HCTL hctl, UINT m, WPARAM wp, LPARAM lp, LONG rc)
{
MSGPARAMS p;
UINT mval = m;
p.MsgVal = &mval;
p.wParam = ℘
p.lParam = &lp;
p.lRetVal= &rc;
VBFireEvent(hctl, IEVENT_MSGBLASTER_MSG, &p);
return rc;
}
//---------------------------------------------------------------------------
// Register custom control. This routine is called by VB when the custom
// control DLL is loaded for use.
//---------------------------------------------------------------------------
BOOL FAR PASCAL _export VBINITCC(USHORT usVersion, BOOL fRuntime)
{
// Avoid warnings on unused (but required) formal parameters
fRuntime = fRuntime;
// Register control(s)
if (usVersion < VB200_VERSION)
return FALSE;
// Register popup class if this is from the development environment.
if (!fRuntime)
{
WNDCLASS class;
class.style = 0;
class.lpfnWndProc = AboutBoxProc;
class.cbClsExtra = 0;
class.cbWndExtra = 0;
class.hInstance = hmodDLL;
class.hIcon = NULL;
class.hCursor = NULL;
class.hbrBackground = NULL;
class.lpszMenuName = NULL;
class.lpszClassName = CLASS_ABOUTBOX;
if (!RegisterClass(&class))
return FALSE;
// Remember the task associated with the development environment
taskDevEnvironment = GetCurrentTask();
}
return VBRegisterModel(hmodDLL, &modelMsgBlaster);
}
//---------------------------------------------------------------------------
// Provide custom control model information to host environment.
//---------------------------------------------------------------------------
LPMODELINFO FAR PASCAL _export VBGetModelInfo(USHORT usVersion)
{
if (usVersion < VB200_VERSION)
return NULL;
else
return &modelinfoMsgBlaster;
}
//---------------------------------------------------------------------------
// Initialize library. This routine is called when the first client loads
// the DLL.
//---------------------------------------------------------------------------
int FAR PASCAL LibMain(HANDLE hModule, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine)
{
// Avoid warnings on unused (but required) formal parameters
wDataSeg = wDataSeg;
cbHeapSize = cbHeapSize;
lpszCmdLine = lpszCmdLine;
hmodDLL = hModule;
return 1;
}
//---------------------------------------------------------------------------
// Unregister the property popup , if this unload
// is from the development environment.
//---------------------------------------------------------------------------
VOID FAR PASCAL _export VBTERMCC()
{
// Unregister popup class if this is from the development environment
if (taskDevEnvironment == GetCurrentTask())
{
UnregisterClass(CLASS_ABOUTBOX, hmodDLL);
taskDevEnvironment = NULL;
}
}
//---------------------------------------------------------------------------
// WEP
//---------------------------------------------------------------------------
// C7 and QCWIN provide default a WEP:
//---------------------------------------------------------------------------
#if (_MSC_VER < 610)
int FAR PASCAL WEP(int fSystemExit);
//---------------------------------------------------------------------------
// For Windows 3.0 it is recommended that the WEP function reside in a
// FIXED code segment and be exported as RESIDENTNAME. This is
// accomplished using the alloc_text pragma below and the related EXPORTS
// and SEGMENTS directives in the .DEF file.
//
// Read the comments section documenting the WEP function in the Windows
// 3.1 SDK "Programmers Reference, Volume 2: Functions" before placing
// any additional code in the WEP routine for a Windows 3.0 DLL.
//---------------------------------------------------------------------------
#pragma alloc_text(WEP_TEXT,WEP)
//---------------------------------------------------------------------------
// Performs cleanup tasks when the DLL is unloaded. WEP() is
// called automatically by Windows when the DLL is unloaded (no
// remaining tasks still have the DLL loaded). It is strongly
// recommended that a DLL have a WEP() function, even if it does
// nothing but returns success (1), as in this example.
//---------------------------------------------------------------------------
int FAR PASCAL WEP(int fSystemExit)
{
// Avoid warnings on unused (but required) formal parameters
fSystemExit = fSystemExit;
return 1;
}
#endif
//---------------------------------------------------------------------------
// ****>>> Aux fn to subclass only valid windows, and only when we're not
// already subclassing a window. Takes care of setting up and maintaining
// the two necessary globals. Returns TRUE if it actually subclassed, FALSE
// otherwise.
//---------------------------------------------------------------------------
BOOL FSubClass(HWND hwnd)
{
int i;
HCTL hctlMain;
if (!IsWindow(hwnd))
return(FALSE); // Invalid hwnd parameter
hctlMain = FindhctlMain(hwnd);
if(!hctlMain)
return(FALSE);
if(i < MAX_MSGBLASTERS)
if (LpblastDEREF(hctlMain)->lpfnOrigProc)
return FALSE; // Already are subclassing
LpblastDEREF(hctlMain)->lpfnOrigProc =
(FARPROC)SetWindowLong(hwnd, GWL_WNDPROC, (DWORD)SubClassProc);
return TRUE;
}
//---------------------------------------------------------------------------
// ****>>> Undo what FSubClass() did. Takes car of clearing out the two
// necessary globals.
//---------------------------------------------------------------------------
VOID UnSubClass(HWND hWndTarget, HCTL hctlMain)
{
PMSGBLASTER pMsgBlaster;
pMsgBlaster = LpblastDEREF(hctlMain);
// Make sure we're actually subclassing before we undo it. if (pMsgBlaster->lpfnOrigProc)
{
SetWindowLong(hWndTarget, GWL_WNDPROC, (LONG)pMsgBlaster->lpfnOrigProc);
pMsgBlaster->lpfnOrigProc = 0L;
pMsgBlaster->hWndTarget = NULL;
}
}
HCTL FindhctlMain(HWND hWnd)
{
int j;
// find the correct hctlMain
for(j = 0; j < MAX_MSGBLASTERS; j++)
{
if(controls[j].hWndTarget == hWnd)
break;
}
return(j == MAX_MSGBLASTERS ? NULL:controls[j].hctlMain);
}
//---------------------------------------------------------------------------
// Create our property popup-window. Since we want to put up a dialog, this
// window never becomes visible. Instead, when asked to become visible, it
// will post a message to itself, remining it to put up our dialog.
//
// NOTE: May return NULL!
//---------------------------------------------------------------------------
HWND NEAR HwndInitAboutBox(VOID)
{
return(CreateWindow(CLASS_ABOUTBOX, NULL, WS_POPUP,
0, 0, 0, 0, NULL, NULL,
hmodDLL, NULL));
}
//---------------------------------------------------------------------------
// We asked to show ourself, remain invisible and post a CM_OPENABOUT to
// ourself. When we receive this message, open the dialog box.
//---------------------------------------------------------------------------
LONG _export FAR PASCAL AboutBoxProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_SHOWWINDOW:
if (wParam)
{
PostMessage(hWnd, CM_OPENABOUTBOX, 0, 0L);
return 0L;
}
break;
case CM_OPENABOUTBOX:
VBDialogBoxParam(hmodDLL, "AboutBox", (FARPROC)AboutBoxDlgProc, 0L);
return 0L;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
//---------------------------------------------------------------------------
// The Dialog Procedure for the AboutBox dialog.
//---------------------------------------------------------------------------
BOOL FAR PASCAL _export AboutBoxDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_INITDIALOG:
{
RECT rect;
int nx, ny; // New x and y
int width, height;
// Position dialog so it looks nice:
GetWindowRect(hDlg, &rect);
width = rect.right - rect.left;
height = rect.bottom - rect.top;
nx = (GetSystemMetrics(SM_CXSCREEN) - width) / 2;
ny = (GetSystemMetrics(SM_CYSCREEN) - height) / 3;
MoveWindow(hDlg, nx, ny, width, height, FALSE);
return TRUE;
}
case WM_COMMAND:
if(wParam == IDOK)
{
EndDialog(hDlg, TRUE);
return TRUE;
}
}
return FALSE;
}
//-- EOF -------------------------------------------------------------------